<template>
  <view :class="{ 'camera-page': true, 'safety-zone-bottom': phoneSafeArea }" :style="`--theme-color: ${color}`">
    <canvas
      v-if="canvasH"
      class="camera-canvas"
      canvas-id="myCanvas"
      :style="{ width: canvasW + 'px', height: canvasH + 'px' }"
    ></canvas>

    <view v-show="!cameraSrc">
      <camera
        class="camera-box"
        mode="normal"
        :device-position="devicePosition"
        resolution="high"
        frame-size="medium"
        output-dimension="max"
        flash="off"
        @error="onChangeError"
      >
        <!-- 取景框 -->
        <cover-view class="camera-aperture" id="frameDom"></cover-view>
        <cover-view class="camera-aperture-line camera-aperture-top"></cover-view>
        <cover-view class="camera-aperture-line camera-aperture-right"></cover-view>
        <cover-view class="camera-aperture-line camera-aperture-bottom"></cover-view>
        <cover-view class="camera-aperture-line camera-aperture-left"></cover-view>
        <cover-view v-if="tipsText" class="camera-aperture-tips">{{ tipsText }}</cover-view>
      </camera>

      <!-- 操作栏 -->
      <view class="camera-control">
        <view class="left-item">
          <!-- <view class="sample">示例</view> -->
        </view>
        <view class="center-item">
          <view class="photo-btn" @click="takePhoto">
            <view class="photo"></view>
          </view>
        </view>
        <view class="right-item">
          <image class="device-pos" src="../../image/switch_icon.png" @click="onDevicePosition" />
        </view>
      </view>
    </view>

    <!-- 图片预览 -->
    <view v-show="cameraSrc" class="camera-img">
      <view class="preview-box">
        <image class="preview" :src="cameraSrc" mode="widthFix" />
      </view>
      <view class="preview-edit">
        <view class="preview-edit-btn" @click="onCancel">取消</view>
        <view class="preview-edit-btn submit-btn" @click="onConfirm">确认</view>
      </view>
    </view>

    <!-- 安全区 -->
    <view v-if="phoneSafeArea" class="safety-zone"></view>
  </view>
</template>

<script>
export default {
  props: {
    // 提示语句
    tipsText: {
      type: String,
      default: '请靠近取景框'
    },

    // 颜色
    color: {
      type: String,
      default: 'rgba(36, 64, 135, 0.8)'
    }
  },

  data() {
    return {
      devicePosition: 'back', // 默认前置
      cameraSrc: '',
      canvasW: 0,
      canvasH: 0,
      pageWidth: 0,
      frameOptions: {}, // 取景框配置信息
      phoneSafeArea: false // 设备安全区
    }
  },

  mounted() {
    uni.getSystemInfo({
      success: res => {
        // 安全区判断
        if (res.safeAreaInsets.bottom) this.phoneSafeArea = true
      }
    })

    this.$nextTick(() => {
      const query = uni.createSelectorQuery().in(this)
      query
        .select('#frameDom')
        .boundingClientRect(data => {
          this.frameOptions = data
          console.log('得到布局位置信息' + JSON.stringify(data))
        })
        .exec()

      // 系统信息
      const winInfo = uni.getSystemInfoSync()
      this.pageWidth = winInfo.windowWidth
    })
  },

  methods: {
    // 取消
    onCancel() {
      this.cameraSrc = ''
    },

    // 确认照片
    onConfirm() {
      this.$emit('onConfirm', { url: this.cameraSrc })
    },

    // 拍照
    takePhoto() {
      const ctx = uni.createCameraContext()
      ctx.takePhoto({
        quality: 'high',
        selfieMirror: true, // 是否开启镜像 默认true
        success: async res => {
          this.cameraSrc = await this.cropImage(res.tempImagePath)
        },
        fail: () => {
          uni.showToast({
            title: '拍照失败，请重试',
            icon: 'none'
          })
        }
      })
    },

    // 裁剪图片
    cropImage(imgUrl) {
      return new Promise((resolve, reject) => {
        uni.getImageInfo({
          src: imgUrl,
          success: file => {
            // 取景框信息
            const options = {
              width: this.frameOptions.width,
              height: this.frameOptions.height,
              y: this.frameOptions.top,
              x: this.frameOptions.left
            }

            const ctx = uni.createCanvasContext('myCanvas', this)

            const proportion = file.width / this.pageWidth
            this.canvasW = file.width / proportion
            this.canvasH = file.height / proportion

            // 绘制图片到canvas，这里可以根据需要裁剪图片
            ctx.drawImage(file.path, 0, 0, this.canvasW, this.canvasH)
            // console.log('drawImage 完成', options)

            // 导出canvas为图片
            ctx.draw(true, () => {
              console.log('canvasToTempFilePath')
              setTimeout(() => {
                // canvas 转 图片
                uni.canvasToTempFilePath(
                  {
                    x: options.x,
                    y: options.y,
                    width: options.width,
                    height: options.height,
                    destWidth: options.width,
                    destHeight: options.height,
                    canvasId: 'myCanvas',
                    fileType: 'jpg',
                    quality: 1,
                    success: res => {
                      resolve(res.tempFilePath)
                    },
                    fail(err) {
                      reject(err)
                    }
                  },
                  this
                )
              }, 500)
            })
          },
          fail(err) {
            reject(err)
          }
        })
      })
    },

    // 保存图片到手机相册
    saveImageToPhone(filePath) {
      uni.saveImageToPhotosAlbum({
        filePath,
        success: () => {
          uni.showToast({
            icon: 'none',
            title: '拍照成功'
          })
        }
      })
    },

    // 切换摄像头
    onDevicePosition() {
      this.devicePosition = this.devicePosition == 'front' ? 'back' : 'front'
    },

    // 监听报错
    onChangeError(e) {
      console.error('camera报错：', e.detail)
    }
  }
}
</script>

<style lang="scss" scoped>
.camera-page {
  --control-h: 200rpx;

  position: fixed;
  top: 0;
  left: 0;
  z-index: 99;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background-color: #fff;

  .camera-box {
    --aperture-t: 30vh;
    --aperture-w: 740rpx;
	--aperture-h: 120rpx;
    --aperture-line: 4rpx;
    --aperture-line-style: 4rpx dashed #fff;
    --edit-padding: 64rpx;

    position: relative;
    width: 100vw;
    height: calc(100vh - var(--control-h));

    .camera-aperture {
      position: absolute;
      top: var(--aperture-t);
      left: 0;
      right: 0;
      width: var(--aperture-w);
      height: var(--aperture-h);
      border-style: dashed;
      border-width: 4rpx;
      border-color: #f9f9f9;
      margin: 0 auto;
      pointer-events: none;
      opacity: 0;
    }

    .camera-aperture-line {
      position: absolute;
      background-color: #fff;
      z-index: 2;
    }

    .camera-aperture-top {
      top: var(--aperture-t);
      left: calc((100vw - var(--aperture-w)) / 2);
      width: var(--aperture-w);
      height: var(--aperture-line);
    }

    .camera-aperture-right {
      top: var(--aperture-t);
      left: calc(var(--aperture-w) + (100vw - var(--aperture-w)) / 2);
      width: var(--aperture-line);
      height: var(--aperture-h);
    }

    .camera-aperture-bottom {
      top: calc(var(--aperture-t) + var(--aperture-h));
      left: calc((100vw - var(--aperture-w)) / 2);
      width: calc(var(--aperture-w) + var(--aperture-line));
      height: var(--aperture-line);
    }

    .camera-aperture-left {
      top: var(--aperture-t);
      left: calc((100vw - var(--aperture-w)) / 2);
      width: var(--aperture-line);
      height: var(--aperture-h);
    }

    .camera-aperture-tips {
      position: absolute;
      top: calc(var(--aperture-t) + 200rpx);
      left: 0;
      right: 0;
      font-size: 32rpx;
      color: #fff;
      max-width: 95%;
      color: #fff;
      text-align: center;
      margin: 0 auto;
    }
  }

  .camera-control {
    width: 100%;
    height: var(--control-h);
    background-color: #fff;
    padding: 0 56rpx;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .left-item {
      width: 25%;
      display: flex;

      .sample {
        font-size: 32rpx;
        color: var(--theme-color);
      }
    }

    .center-item {
      width: 50%;
      display: flex;
      align-items: center;

      .photo-btn {
        width: 140rpx;
        height: 140rpx;
        border: 4rpx solid var(--theme-color);
        border-radius: 50%;
        padding: 10rpx;
        box-sizing: border-box;
        margin: 0 auto;

        .photo {
          width: 100%;
          height: 100%;
          border-radius: 50%;
          background-color: var(--theme-color);
        }
      }
    }

    .right-item {
      width: 25%;
      display: flex;
      justify-content: flex-end;

      .device-pos {
        width: 66rpx;
        height: 66rpx;
      }
    }
  }

  .camera-img {
    position: relative;
    width: 100vw;
    z-index: 9999;

    .preview-box {
      width: 100%;
      height: calc(100vh - var(--control-h));
      background-color: #f5f5f5;
      display: flex;
      align-items: center;
      justify-content: center;

      .preview {
        width: 100%;
        height: 100%;
      }
    }

    .preview-edit {
      width: 100%;
      height: var(--control-h);
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0 60rpx;
      box-sizing: border-box;
      background-color: #fff;
      // box-shadow: 0 -4rpx 12rpx rgba(158, 158, 158, 0.05);
      z-index: 9;

      .preview-edit-btn {
        padding: 16rpx 36rpx;
        border-radius: 12rpx;
        background-color: #fff;
        font-size: 32rpx;
        line-height: 1;
        color: #565656;
        font-weight: bold;
      }

      .submit-btn {
        // background-color: var(--theme-color);
        // color: #fff;
        color: var(--theme-color);
      }
    }
  }

  .camera-canvas {
    position: fixed;
    top: 200vh;
    left: 0;
    z-index: -999;
    opacity: 0;
  }
}

// 安全底部
.safety-zone-bottom {
  --safety-zone-bottom: 34px;

  .camera-img > .preview-box,
  .camera-box {
    height: calc(100vh - var(--control-h) - var(--safety-zone-bottom));
  }

  .safety-zone {
    height: var(--safety-zone-bottom);
    width: 100%;
    background-color: inherit;
    z-index: 9999;
  }
}
</style>
